package org.springframework.beans.factory.xml;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.CollectionUtils;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class PluggableSchemaResolver implements EntityResolver {

    private static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
    
    private final ClassLoader classLoader;
    
    private final String schemaMappingsLocation;
    
    private Map<String, String> schemaMappings;
    
    public PluggableSchemaResolver(ClassLoader classLoader) {
        this.classLoader = classLoader;
        schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
    }
    @Override
    public InputSource resolveEntity(String publicId, String systemId)
            throws SAXException, IOException {
        if (systemId != null) {
            String resourceLocation = getSchemaMappings().get(systemId);
            Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
            InputSource source = new InputSource(resource.getInputStream());
            source.setPublicId(publicId);
            source.setSystemId(systemId);
            return source;
        }
        return null;
    }

    private Map<String, String> getSchemaMappings() {
        if (this.schemaMappings == null) {
            synchronized(this) {
                if (this.schemaMappings == null) {
                    try {
                        Properties props = PropertiesLoaderUtils.loadAllProperties(schemaMappingsLocation, classLoader);
                        Map<String, String> schemaMappings = new ConcurrentHashMap<String, String>();
                        CollectionUtils.mergePropertiesIntoMap(props, schemaMappings);
                        this.schemaMappings = schemaMappings;
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
        return this.schemaMappings;
    }
}
